/*
Rewrite of ByteArray.hpp
10.24.2011
By math4tots

Since bytes are read one at a time, byte-level endianness is not too important.

As for bit level access, I assume little-endian. According to wikipedia (http://en.wikipedia.org/wiki/Endianness#.22Bit_endianness.22) most hardware uses little-endian so for simplicity that's what I'm going to assume.
*/
#ifndef ByteArray_HPP
#define ByteArray_HPP
#include"ByteUtil.hpp"
#include<string.h>
namespace std{
class ByteArray{
public:
	//(Constructor)
	ByteArray(const char* filename);
	ByteArray(const char* data, long nbytes);
		
	//(Destructor)
	~ByteArray();
	
	//Copying
	//ByteArray(ByteArray other);
	//bool operator=(ByteArray other);
	
	//Input/Output
	void save(const char* filename);
	void load(const char* filename);
	
	//Capacity
	size_t size();
	
	//Byte Access
	char& operator[](size_t index);
	char* operator()(size_t index);
	ByteArray operator()(size_t a, size_t b);
	
	//Bit Access
	void setBit (long pos, bool val);
	bool getBit (long pos);
	unsigned long long intBits (long pos, long nbits);
	
private:
	char* data;
	size_t filesize;
};


//Method implementation
//(Constructor)
//It is important when an object is constructed that "data" has a value explicitly defined.
//Otherwise, destructor will call "delete[] data", and produce undefined behavior.

	ByteArray::ByteArray(const char* filename){data = NULL; load(filename);}
	ByteArray::ByteArray(const char* data, long nbytes) {
		//allocate data for my new ByteArray
		this->data = new char[nbytes];
		
		//copy data into this ByteArray
		memcpy(this->data, data, nbytes);
	}

//(Destructor)
	ByteArray::~ByteArray(){delete[] data;}
	
//Copying
/*
	ByteArray::ByteArray(ByteArray other){
		//allocate memory
		data = new char[other.size()];
		
		//copy data into this ByteArray
	}
*/	
//Input/Output
	void ByteArray::save(const char* filename){
		//open file to write to
		ofstream fout(filename);
		
		//write to the file.
		fout.write(data, filesize);
		
		//close file
		fout.close();
	}
	void ByteArray::load(const char* filename){
		//clear out whatever was there before.
		delete[] data;
		//open the file
		ifstream fin(filename);
		
		//get the file size, so I know how much data to allocate,
		//also, I do need to keep track of new file size.
		filesize = ifstreamFileSize(fin);
		
		//allocate data.
		data = new char[filesize];
		
		//actually read in the data
		fin.read(data, filesize);
		
		//close the file
		fin.close();
	}
	
//Capacity
	size_t ByteArray::size() { return filesize; }
	
//Byte Access
	char& ByteArray::operator[](size_t index){return data[index];}
	char* ByteArray::operator()(size_t index){return data + index;}
	ByteArray ByteArray::operator()(size_t a, size_t b){ return ByteArray(data + a,b-a); }
	
//Bit Access
	void ByteArray::setBit (long pos, bool val){
		//figure out which byte we are interested in.
		size_t byte = pos/8;
		//figure out which bit we are interested in.
		short bit = pos%8;
		
		//create a byte with desired bit marked.
		unsigned char mark = 1; //little-endian assumes 1 marks the first bit.
		mark <<= bit; //we move that 1 bit moves as much as we need it to.
		
		//Now actually set the desired bit to the desired values
		if (val) data[byte] |= mark;
		else data[byte] ^= mark;
	}
	
	bool ByteArray::getBit (long pos){
		//figure out which byte we are interewstd in.
		long byte = pos/8;
		//figure out which bit we are interested in.
		short bit = pos%8;
		
		//create a byte with desired bit marked.
		unsigned char mark = 1; //little-endian assumes 1 marks the first bit.
		mark <<= bit; // we move that 1 bit moves as much as we need it to.
		
		//consider data[byte] ^ mark (bitwise and).
		//If the desired bit is 0, the result should be zero.
		//If the desired bit is 1, the desired bit of the result should be 1, i.e., nonzero.
		return (data[byte] & mark) != 0;
	}
	
	//interpret the bits.
	unsigned long long ByteArray::intBits (long pos, long nbits = 8){
		unsigned long long ret = 0;
		for (int i = pos + nbits - 1; i >= pos; i--){
			ret <<= 1;
			ret += getBit(i);
		}
		return ret;
	}
	
}

#endif//ByteArray_HPP